#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

#define N 4000000
/* #define DEBUG 0 */

typedef struct s_pixel_rgb {
  float* r;
  float* g;
  float* b;
} t_pixel_rgb;

typedef struct s_pixel_yuv {
  float* y;
  float* u;
  float* v;
} t_pixel_yuv;

#define iter(i) \
    yuv.y[i] = 0.299 * rgb.r[i] + 0.587 * rgb.g[i] + 0.114 * rgb.b[i]; \
    yuv.u[i] = 0.492 * (rgb.b[i] - (0.299 * rgb.r[i] + 0.587 * rgb.g[i] + 0.114 * rgb.b[i])); \
    yuv.v[i] = 0.877 * (rgb.r[i] - (0.299 * rgb.r[i] + 0.587 * rgb.g[i] + 0.114 * rgb.b[i]));

void rgb_to_yuv(t_pixel_rgb rgb, t_pixel_yuv yuv, int len, int N_iter)
{
  int i,j;

  for (j=0; j<N_iter; j++)
  {
    for (i=0; i<len-3; i+=4) {
      iter(i+0);
      iter(i+1);
      iter(i+2);
      iter(i+3);
    }
    for (i=0; i<len; i++) {
      iter(i);
    }
  }
}

int main (int argc, char *argv[])
{
  t_pixel_rgb rgb; t_pixel_yuv yuv; // Vectores para malloc

  int i;
  int n=N; // tamanyo vectores
  int NIt=50; // Num.iters

  if (argc>1) NIt = atoi(argv[1]);
  if (argc>2) n = atoi(argv[2]);

  if (n>N) { printf("Maxima longitud vector: %d\n",N); exit(-1); }

  if (posix_memalign((void**)&(rgb.r), 8, n*sizeof(float)*3) !=0) {
      fprintf(stderr, "No memory.\n");
      exit(-1);
  }
  rgb.g = &(rgb.r[n*1]);
  rgb.b = &(rgb.r[n*2]);

  if (posix_memalign((void**)&(yuv.y), 8, n*sizeof(float)*3) !=0) {
      fprintf(stderr, "No memory.\n");
      exit(-1);
  }
  yuv.u = &(yuv.y[n*1]);
  yuv.v = &(yuv.y[n*2]);

  for (i=0;i<n;i++) {
     rgb.r[i]=(float) ((i<<26) ^ ((i + 340) << 22) ^ i ^ 0xf215fabc);
     rgb.g[i]=(float) (((i+450)<<27) ^ ((i + 567) <<20) ^ i ^ 0xb152e8ca);
     rgb.b[i]=(float) (((i+7823454) << 25) ^0xbad51cde);
  }

  rgb_to_yuv(rgb, yuv, n, NIt);

  // Rearrange to preserve original output
  for (i=0;i<n;i++) {
    rgb.r[i*3+0] = yuv.y[i];
    rgb.r[i*3+1] = yuv.u[i];
    rgb.r[i*3+2] = yuv.v[i];
  }
  write(1, rgb.r, n*sizeof(float)*3);
  return(0);
}
